package com.demo.webapp.context;

import java.lang.reflect.Method;
import java.util.Map;

import org.springframework.util.ReflectionUtils;

import com.demo.common.AopProxyUtils;
import com.opensymphony.xwork2.DefaultActionInvocation;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.opensymphony.xwork2.util.profiling.UtilTimerStack;

public class ProxyActionInvocation extends DefaultActionInvocation {

	/**
	 * 版本序列化ID
	 */
	private static final long serialVersionUID = 5303681979247326855L;
	
	private static final Logger LOG = LoggerFactory.getLogger(DefaultActionInvocation.class);
	private static final Class[] EMPTY_CLASS_ARRAY   = new Class[0];
	private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
	    
	public ProxyActionInvocation(Map<String, Object> extraContext, boolean pushAction) {
		super(extraContext, pushAction);
	}

    public Object getAction() {
        return action;
    }
    
    protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
        String methodName = proxy.getMethod();

        if (LOG.isDebugEnabled()) {
            LOG.debug("Executing action method = " + actionConfig.getMethodName());
        }

        String timerKey = "invokeAction: " + proxy.getActionName();
        try {
            UtilTimerStack.push(timerKey);

            boolean methodCalled = false;
            Object methodResult = null;
            Method method = null;
            try {
            	//Object action = invocation.getAction();
                // ???
            	//Object actionTemp = AopProxyUtils.ultimateTargetObject(getAction());
            	//org.springframework.aop.framework.
            	// 得到真实方法(Action有可能是AOP代理对象)
                method = AopProxyUtils.ultimateTargetClass(getAction()).getMethod(methodName, EMPTY_CLASS_ARRAY);
                //org.springframework.util.ReflectionUtils.
               // org.springframework.aop.framework.ReflectiveMethodInvocation.
                
            } catch (NoSuchMethodException e) {
                // hmm -- OK, try doXxx instead
                try {
                    String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
                    method = getAction().getClass().getMethod(altMethodName, EMPTY_CLASS_ARRAY);
                } catch (NoSuchMethodException e1) {
                    // well, give the unknown handler a shot
                    if (unknownHandlerManager.hasUnknownHandlers()) {
                        try {
                            methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
                            methodCalled = true;
                        } catch (NoSuchMethodException e2) {
                            // throw the original one
                            throw e;
                        }
                    } else {
                        throw e;
                    }
                }
            }

            if (!methodCalled) {
            	//ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(action , AopProxyUtils.ultimateTargetObject(getAction()), method, EMPTY_OBJECT_ARRAY,
            	//		AopProxyUtils.ultimateTargetClass(getAction()), null);
//            	if (action instanceof TargetClassAware) {
//            		// Action是代理对象
//            		methodResult = ReflectionUtils.invokeMethod(method, AopProxyUtils.ultimateTargetObject(getAction()));
//            	} else {
//            		// Action非代理对象
//            		methodResult = ReflectionUtils.invokeMethod(method, action);
//            	}
            	methodResult = ReflectionUtils.invokeMethod(method, action);
            }

            return saveResult(actionConfig, methodResult);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
        } catch (Throwable e) {
            // We try to return the source exception.
            //Throwable t = e.getTargetException();

            if (actionEventListener != null) {
                String result = actionEventListener.handleException(e, getStack());
                if (result != null) {
                    return result;
                }
            }
            if (e instanceof Exception) {
                throw (Exception) e;
            } else {
                throw new Exception(e);
            }
        } finally {
            UtilTimerStack.pop(timerKey);
        }
    }
}